<?php
/**
 * 根据一个表的数据绘制图形
 * 只要有FDate和FValue两个字段
 * */

require_once(LIB_PATH.'/color/mycolor.php');
$path = LIB_PATH.'/chart/';
set_include_path(get_include_path() . PATH_SEPARATOR . $path);
require_once('OFC/OFC_Chart.php');


error_reporting(E_ERROR);

class mychart{
	var $chart;
	var $barDataSet;
	var $lineDataSet;
	var $title =  ' ';//图片的标题
	var $allowNeg = false; //纵坐标是否允许负数




	/**
	 * 运行纵坐标显示负数
	 * */
	public function allowYNeg(){
		$this->allowNeg = true;
	}


	public function __construct(){
		$this->chart = new OFC_Chart();
	}

	/**
	 * 设置URL
	 * */
	public function setBaseUrl($url){
		$this->url = $url;
	}



	/**
	 * 增加基础数据
	 * @param $data 一定要有FDate和FValue两个字段
	 * @param $cacheFile 缓存文件名
	 * @param $graphType 注意默认json用png需用GET[type]指定
	 * @param $delayDays 当前数据相对于深圳成指滞后的天数
	 * @param $indexType 指数默认sz,pig表示鸭指
	 * */
	public function addBaseData($data,$cacheFile='',$graphType='line',$delayDays=0,$indexType='sz'){
		$db = new mydb();
		$this->emptyArray = array(); //用来控制多组数据的颜色显示情况
		$this->trueDays   = array();//真实的日期序列
		$this->szIndex    = array();//深圳成指序列
		$this->values = array();
		$this->data   = $data;
		$this->delayDays = $delayDays;
		$num = count($this->data);
		for ($i = 0; $i < ($num  + $delayDays );$i++){

			if($i == $num){//计算一次均值
				$vatualData = array_sum($this->values) / count($this->values); //虚拟数据值
			}

			if($i < $num){//有发布数据
				$day = $this->data[$i]['FDate'];//可以前推网签日
				$this->values[] = $this->data[$i]['FValue'];
				$standDay = substr($day,0,4).'-'.substr($day,4,2).'-'.substr($day,6,2).' 08:00:00';
				$szTime = strtotime($standDay) - $delayDays * 24 * 3600;
			}else {//预测还没有发布的数据
				$day = $this->data[$num-1]['FDate'];//最后一天
				$this->values[] = $vatualData;//构造无效空数据 //构建一个均值为虚拟数据，避免0值为实际有效值时，产生图像的偏移
				//$this->values[] = NULL;//构造无效空数据
				$standDay = substr($day,0,4).'-'.substr($day,4,2).'-'.substr($day,6,2).' 08:00:00';
				$szTime = strtotime($standDay) - ($delayDays- ($i - $num +1) ) * 24 * 3600;
			}

			$szDay  = date('Ymd',$szTime);

			$this->trueDays[] = $szDay;
			$this->emptyArray[] = 0;
			if($indexType=='pig'){
				$this->szIndex[] = get_pig_index($szDay,$db);
				$this->indexName = 'duckindex';
			}else{
				$this->szIndex[] = get_sz_index($szDay,$db);
				$this->indexName = 'szindex';
			}
		}//end for

		$this->fuquanDays = fuquan_day($this->trueDays);//复权后的日期序列


		$this->avg7Val = array();//每7天的均值
		$avgLen  = 7; //长度
		for ($j = 0; $j < count($this->values); $j++){
			$newVals = array(); //重置7天的数组
			for($k = 0; $k<$avgLen; $k++){
				if($j - $k >=0){
					$newVals[] = $this->values[$j-$k];
				}
			}
			$this->avg7Val[] = array_sum($newVals)/count($newVals);
		}
		$this->fuquanAvg7Val = fuquan($this->avg7Val);
		$this->fuquanValues  = fuquan($this->values);

		//----计算最新变化-----------------
		$this->todayValue = $this->fuquanValues[count($this->fuquanValues)-1];
		$this->yesterdayValue = $this->fuquanValues[count($this->fuquanValues)-2];
		$this->changeValue   = round($this->todayValue-$this->yesterdayValue,5);
		$this->changePercent = round($this->changeValue/abs($this->yesterdayValue) * 100 ,2) ;
		if($this->changeValue > 0 ){
			$this->changeValue   = '+'.$this->changeValue;
			$this->changePercent = '+'.$this->changePercent;
		}

		$this->changeInfo  = $this->title.' '.date('Y年m月d日',strtotime($this->data[count($this->data)-1]['FDate'].' 00:00:00'));
		$this->changeInfo .= ' 最新指数:'.round($this->values[count($this->values)-1],4);
	}

	/**
	 * @param $data 一定要有FDate和FValue两个字段
	 * @param $cacheFile 缓存文件名
	 * @param $graphType 注意默认json用png需用GET[type]指定
	 * @param $delayDays 当前数据相对于深圳成指滞后的天数
	 * @param $indexType 指数默认sz,pig表示鸭指
	 * */
	public function draw($data,$cacheFile='',$graphType='line',$delayDays=0,$indexType='sz'){
		$this->addBaseData($data,$cacheFile,$graphType,$delayDays,$indexType);
		$this->jsonDraw($indexType);
	}

	/**
	 * 打印json数据
	 * */
	public function jsonDraw($indexType){
		$detailValues = array();
		$num = count($this->fuquanValues);

		$this->allTimestamp = array();
		$emotion   = array(); //表情
		$sortedValues = $this->fuquanValues;
		sort($sortedValues);//排序好的values
		for($i = 0; $i < $num; $i++){
			$time = strtotime($this->trueDays[$i].' 00:00:00');
			$this->allTimestamp[]  = $time;
			//$tip   = 'Y:'.round($this->fuquanValues[$i],3).'<br>';
			$tip  = 'VAL:'.round($this->values[$i],4).'<br>';
			$tip  .= '7AVG:'.round($this->avg7Val[$i],4).'<br>';
			//$tip .= '7AVG_SRC:'.round($this->avg7Val[$i],2).'<br>';
			$tip  .= $this->indexName.':'.round($this->szIndex[$i],2).'<br>';
			$tip  .= 'DATE:'.date('Y-m-d',$time).'<br>';



			$numValues = count($sortedValues);
			if($this->fuquanValues[$i] < $sortedValues[ intval($numValues * 0.15) ] ){
				$color = mycolor::$hexDarkGreen;
				$emotion[] = '~~~^_^~~~';

			}elseif ($this->fuquanValues[$i]< $sortedValues[ intval($numValues * 0.4) ] ){
				$color = mycolor::$hexBlue;
				$emotion[] = 'Y(^_^)Y';
			}else if($this->fuquanValues[$i]<$sortedValues[ intval($numValues * 0.7) ] ){
				$color = mycolor::$hexYellow;
				$emotion[] = '⊙_⊙';
			}else{
				$color = mycolor::$hexBlack;
				$emotion[] = '(╯^╰〉';
			}
			$tip  .= $emotion[$i];

			$curUrl = null;
			if($this->url != ''){
				$curUrl = $this->url.",beginDate,".$this->trueDays[$i];
			}
			if(isset($this->data[$i]['FIsPredict']) && $this->data[$i]['FIsPredict']==1){
				$tip .= '<br>当前为预估值';
			}

			$detailValues[] = array(
			"x"    => $time,
			"value"=> $this->fuquanValues[$i], //实际是日线了
			"tip"  => $tip,
			"colour"=>$color,
			"on-click"=> $curUrl
			);



		}

		$lineValues = new OFC_Charts_Line();
		$lineValues->width = 1;
		$lineValues->set_values( $detailValues );//设置单个值的颜色
		$lineValues->text= $this->title;
		$lineValues->{'dot-style'} = array(
		'type'    => "solid-dot",
		'colour'  => mycolor::$hexRed,
		'dot-size'=> 2,
		'halo-size'=>0
		);//设置曲线折点的样式:star、anchor、hollow-dot
		$lineValues->{"colour"} = mycolor::$hexRed; //设置线条颜色



		//------------股指---------------
		$detailSzIndex = array();
		$this->fuquanSzIndex = fuquan($this->szIndex);
		$num = count($this->szIndex);
		for($i = 0; $i < $num; $i++){
			$tip  = $this->indexName.':'.round($this->szIndex[$i],2).'<br>';
			//$tip .= 'INDEX_VAL:'.$this->fuquanSzIndex[$i].'<br>';
			//$tip .= '1DAY_VAL:'.round($this->fuquanValues[$i],3).'点<br>';
			//$tip .= '7AVG_VAL:'.round($this->fuquanAvg7Val[$i],3).'点<br>';
			$tip .= 'DATE:'.date('Y-m-d',strtotime($this->trueDays[$i].' 00:00:00')).'<br>';
			//$tip .= $emotion[$i];

			$detailSzIndex[] = array(
			"x"        => $this->allTimestamp[$i],
			"value"    => $this->fuquanSzIndex[$i],
			"tip"      => $tip
			);
		}
		$lineSzIndex = new OFC_Charts_Line(); //柱状图
		$lineSzIndex->set_values( $detailSzIndex ); //设置个性的提示
		$lineSzIndex->set_colour(mycolor::$hexGray);
		$lineSzIndex->width = 1;
		/*		$lineSzIndex->{'dot-style'} = array(
		'type'    => "solid-dot",
		'colour'  => mycolor::$hexGreen,
		'dot-size'=> 2
		);*/
		$lineSzIndex->alpha = 0.95;
		if($indexType=='sz'){
			$lineSzIndex->text='深圳成指';
		}else{
			$lineSzIndex->text='破浪交易线';
		}

		//------------标注延期天数的数据的真实发布时间-----
		if($this->delayDays > 0) {
			$pos = count($this->trueDays)-$this->delayDays-1;
			$time = strtotime($this->trueDays[$pos].' 00:00:00');
			$minY = -0.05 + $this->fuquanValues[$pos];
			$maxY = 0.05 + $this->fuquanValues[$pos];
			$tip  = '最新值'.round($this->values[$pos],3).'<br>最新值实际日期'.$this->trueDays[$pos].'<br>数据发布日期'.$this->trueDays[count($this->trueDays)-1];
			mychart::addVLine($this->chart,$time,$tip,$minY,$maxY,mycolor::$hexPurple);
		}


		//纵坐标标注
		//$this->chart->y_legend->text= $this->title;
		//$this->chart->y_legend->style = 'font-size:12px;';

		//图像标题
		$title = new OFC_Elements_Title( $this->changeInfo );
		$this->chart->set_title( $title ); //设置中文title


		$this->chart->set_bg_colour(mycolor::$hexWhite);
		//$this->chart->add_element( $bar ); //加入每天值
		$this->chart->add_element( $lineValues ); //7日均线
		$this->chart->add_element( $lineSzIndex );//股指



		$this->chart->y_axis->steps=10; //step定义了多长距离显示一个label，跟具体图形无关
		$this->chart->y_axis->max=100;  //纵向最大值，注意，这个值不能为负数
		$this->chart->y_axis->min=-$this->chart->y_axis->max; //纵向最小值

		//根据 $pig_indexes 和对应的 $fuquanPigIndexs 计算 $yLabels
		//寻找第一个正值对应索引
		for ($objIndex = 0; $objIndex< $num; $objIndex++){
			if($this->fuquanValues[$objIndex] > 0){
				break;
			}
		}
		//寻找第一个负值对应索引
		for ($negIndex = 0; $negIndex< $num; $negIndex++){
			if($this->fuquanValues[$negIndex] < 0){
				break;
			}
		}
		//计算起始高度
		$objYHeight = $this->fuquanValues[$objIndex] + $this->chart->y_axis->max; //正值高度
		$negYHeight = $this->fuquanValues[$negIndex] + $this->chart->y_axis->max; //负值高度

		$startYpig = ($this->values[$negIndex] * $objYHeight - $this->values[$objIndex] * $negYHeight ) / ($objYHeight - $negYHeight);
		//die($startYpig.'=$startYpig');
		$curHeightY = $this->fuquanValues[$objIndex] + $this->chart->y_axis->max;
		$perY       =  ($this->values[$objIndex] - $startYpig) / $curHeightY;//每单位的Y对应的pig值
		//die($perY.'=$perY');

		$minValue = min($this->values);
		$maxValue = max($this->values);
		$yLabels = array();
		for ($i = 0; $i < ($this->chart->y_axis->max - $this->chart->y_axis->min); $i++){
			$intLen = strlen(round($perY * $i + $startYpig));//整数部分长度，保持最少个数字，不够从后边小数补齐
			$roundLen = (4 - $intLen) > 0?(4 - $intLen):0;
			$labelVal = round($perY * $i + $startYpig,$roundLen);

			if($this->allowNeg || $labelVal > 0){//
				$yLabels[$i] = ''.$labelVal.'';
			}else {
				$yLabels[$i] = '';
			}
		}

		//print_r($yLabels);

		$this->chart->y_axis->labels->labels = $yLabels; //注意label的值一定要用string类型



		//----设置纵坐标--------------
		$this->chart->x_axis->min  = $this->allTimestamp[0];
		$this->chart->x_axis->max  = $this->allTimestamp[count($this->allTimestamp) - 1];
		$this->chart->x_axis->steps= 86400 * 60; //step定义了多长距离显示一个label，跟具体图形无关
		$this->chart->x_axis->labels = array(
		'visible-steps'=> 10,
		'rotate'=>315,
		'text'  =>"#date:Y-m#"
		);

		//---------设置菜单------------
		$this->chart->menu->colour = "#E0E0ff";
		$this->chart->menu->{"outline-colour"} = "#707070";
		$this->chart->menu->values = array(
		array("type"=>'text',"text-colour"=>"#FF0000","text"=>"全部数据","javascript-function"=>"showFullImage"),
		array("type"=>'text',"text"=>"1000PX","javascript-function"=>"zoom(1000)"),
		array("type"=>'text',"text"=>"1600PX","javascript-function"=>"zoom(1600)"),
		array("type"=>'text',"text"=>"4000PX","javascript-function"=>"zoom(4000)"),
		 
		);


		echo $this->chart->toString(); //打印json数据
	}


	public function setTitle($title){
		$this->title = $title;
	}

	/**
	 * 增加一个柱形图
	 * */
	public function addBar($values,$lineName='',$color=''){
		$barChart = new OFC_Charts_Bar();
		$barChart->set_values( fuquan($values) );
		$barChart->alpha = 0.5;
		$barChart->set_colour($color); //设置颜色
		$barChart->text = $lineName;
		$this->chart->add_element( $barChart );//股指

	}


	/**
	 * 增加一个线条图形
	 * */
	public function addLine($values,$lineName='',$color=''){
		if($color==''){
			$color = mycolor::$hexPurple;
		}


		$this->fuquanLV = fuquan($values);
		$detailValues = array();
		$num = count($this->fuquanLV);
		$this->allTimestamp = array();
		$emotion   = array(); //表情
		$sortedValues = $this->fuquanLV;
		sort($sortedValues);//排序好的values
		for($i = 0; $i < $num; $i++){
			$time = strtotime($this->trueDays[$i].' 00:00:00');
			$this->allTimestamp[]  = $time;
			$tip   = 'Y:'.round($this->fuquanLV[$i],3).'<br>';
			$tip  .= '1DAY_VAL:'.round($values[$i],3).'<br>';
			//$tip  .= '7AVG_VAL:'.round($this->avg7Val[$i],3).'<br>';
			//$tip .= '7AVG_SRC:'.round($this->avg7Val[$i],2).'<br>';
			$tip  .= $this->indexName.':'.round($this->szIndex[$i],2).'<br>';
			$tip  .= 'DATE:'.date('Y-m-d',$time).'<br>';



			$numValues = count($sortedValues);
			if($this->fuquanLV[$i] < $sortedValues[ intval($numValues * 0.15) ] ){
				//$color = mycolor::$hexDarkGreen;
				$emotion[] = '~~~^_^~~~';

			}elseif ($this->fuquanLV[$i]< $sortedValues[ intval($numValues * 0.4) ] ){
				//$color = mycolor::$hexBlue;
				$emotion[] = 'Y(^_^)Y';
			}else if($this->fuquanLV[$i]<$sortedValues[ intval($numValues * 0.7) ] ){
				//$color = mycolor::$hexYellow;
				$emotion[] = '⊙_⊙';
			}else{
				//$color = mycolor::$hexBlack;
				$emotion[] = '(╯^╰〉';
			}
			$tip  .= $emotion[$i];
			$detailValues[] = array(
			"x"    => $time,
			"value"=> $this->fuquanLV[$i], //实际是日线了
			"tip"  => $tip,
			"colour"=>$color,
			"on-click"=> "http://www.polang.org/duck,predict?ofc=duck,predictJson,beginDate,".$this->trueDays[$i]
			);
		}
		$lineValues = new OFC_Charts_Line();
		$lineValues->width = 1;
		$lineValues->set_values( $detailValues );//设置单个值的颜色
		$lineValues->text=$lineName;
		$lineValues->{'dot-style'} = array(
		'type'    => "solid-dot",
		'colour'  => mycolor::$hexRed,
		'dot-size'=> 1,
		'halo-size'=>0
		);//设置曲线折点的样式:star、anchor、hollow-dot
		$lineValues->{"colour"} =$color; //设置线条颜色

		$this->chart->add_element( $lineValues );

		/*		$line = new OFC_Charts_Line();
		$line->set_values($detailValues);
		$line->set_colour($color);
		$this->chart->add_element( $line );*/

	}



	/**
	 * 添加一个垂直线
 	 * @param $this->chart 图形
 	 * @param $x 竖线的横坐标
 	 * @param $tip 鼠标移动上去，需要显示的内容
  	 * @param $minY 竖线的底部纵坐标
 	 * @param $maxY 竖线的顶部纵坐标
 	 * @param $color mycolor::$hexRed颜色
 	 * */
	public  static function addVLine($chart,$x,$tip='',$minY=-1,$maxY=1,$color=''){
		if($color==''){
			$color = mycolor::$hexRed;
		}

		$line = new OFC_Charts_Line();
		$pointLow    = array("x"=>$x,"y"=>$minY,"tip"=>$tip);
		$pointMiddle = array("x"=>$x,"y"=>($minY+$maxY)/2,"tip"=>$tip);
		$pointHigh   = array("x"=>$x,"y"=>$maxY,"tip"=>$tip);
		$values = array($pointLow , $pointMiddle , $pointHigh);
		$line->set_values($values);
		$line->set_colour($color);
		$chart->add_element( $line );
	}
}
?>